package com.fish.web.controller;

import com.fish.common.exception.BusinessException;
import com.fish.common.result.Result;
import com.fish.common.result.ResultCode;
import com.fish.common.util.JwtUtil;
import com.fish.model.vo.LoginVO;
import com.fish.model.vo.UserVO;
import com.fish.service.TokenService;
import com.fish.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * 认证Controller
 */
@Tag(name = "认证管理", description = "用户认证相关接口，包括登录、注册、退出、Token刷新等")
@Slf4j
@RestController
@RequestMapping("/api/auth")
public class AuthController {
    
    @Autowired
    private TokenService tokenService;
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private com.fish.common.service.VerificationCodeService verificationCodeService;
    
    @Autowired
    private com.fish.common.service.CaptchaService captchaService;
    
    /**
     * 刷新Token
     */
    @Operation(summary = "刷新Token", description = "使用Refresh Token获取新的Access Token和Refresh Token")
    @ApiResponses({
        @ApiResponse(responseCode = "200", description = "刷新成功", content = @Content(schema = @Schema(implementation = LoginVO.class))),
        @ApiResponse(responseCode = "401", description = "Refresh Token无效或已过期")
    })
    @PostMapping("/refresh")
    public Result<LoginVO> refreshToken(@RequestBody RefreshTokenRequest request) {
        String refreshToken = request.getRefreshToken();
        
        // 1. 验证Refresh Token是否有效
        if (!tokenService.validateRefreshToken(refreshToken)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID.getCode(), "Refresh Token无效或已过期");
        }
        
        // 2. 检查Token是否在黑名单中
        if (tokenService.isInBlacklist(refreshToken)) {
            throw new BusinessException(ResultCode.TOKEN_INVALID.getCode(), "Token已失效");
        }
        
        // 3. 从Refresh Token中获取用户信息
        Long userId = JwtUtil.getUserId(refreshToken);
        String username = JwtUtil.getUsername(refreshToken);
        
        // 4. 生成新的Access Token和Refresh Token
        String newAccessToken = JwtUtil.generateAccessToken(userId, username);
        String newRefreshToken = JwtUtil.generateRefreshToken(userId, username);
        
        // 5. 保存新的Refresh Token（会自动删除旧的）
        tokenService.saveRefreshToken(userId, newRefreshToken);
        
        // 6. 将旧的Refresh Token加入黑名单
        tokenService.addToBlacklist(refreshToken, userId, "refresh");
        
        // 7. 获取用户信息
        UserVO userVO = userService.getUserById(userId);
        
        // 8. 返回新的Token
        LoginVO loginVO = new LoginVO(newAccessToken, newRefreshToken, userVO);
        log.info("Token刷新成功，userId: {}", userId);
        
        return Result.success("Token刷新成功", loginVO);
    }
    
    /**
     * 退出登录
     */
    @Operation(summary = "退出登录", description = "退出登录，将Token加入黑名单")
    @Parameter(name = "Authorization", description = "认证Token（格式：Bearer {token}）", required = true, in = ParameterIn.HEADER)
    @PostMapping("/logout")
    public Result<Void> logout(@RequestHeader("Authorization") String authHeader) {
        // 1. 提取Token
        String token = authHeader.replace("Bearer ", "");
        
        // 2. 验证Token
        if (!JwtUtil.validateToken(token)) {
            return Result.success("退出成功", null);
        }
        
        // 3. 获取用户信息
        Long userId = JwtUtil.getUserId(token);
        
        // 4. 将Access Token加入黑名单
        tokenService.addToBlacklist(token, userId, "logout");
        
        // 5. 删除Refresh Token
        tokenService.deleteRefreshToken(userId);
        
        log.info("用户退出登录成功，userId: {}", userId);
        return Result.success("退出成功", null);
    }
    
    /**
     * 生成图形验证码
     */
    @Operation(summary = "生成图形验证码", description = "生成图形验证码，返回验证码ID和Base64编码的图片")
    @GetMapping("/captcha")
    public Result<com.fish.common.service.CaptchaService.CaptchaVO> getCaptcha() {
        com.fish.common.service.CaptchaService.CaptchaVO captcha = captchaService.generateCaptcha();
        return Result.success("验证码生成成功", captcha);
    }
    
    /**
     * 发送邮箱验证码
     */
    @Operation(summary = "发送邮箱验证码", description = "发送邮箱验证码用于注册或登录")
    @Parameters({
        @Parameter(name = "email", description = "邮箱地址", required = true, example = "user@example.com"),
        @Parameter(name = "type", description = "验证码类型（login-登录, register-注册）", required = true, example = "register")
    })
    @PostMapping("/send-code")
    public Result<Void> sendEmailCode(@RequestParam String email, @RequestParam String type) {
        log.info("发送邮箱验证码，邮箱：{}，类型：{}", email, type);
        
        // 检查邮箱状态
        boolean emailExists = userService.checkEmailExists(email);
        
        if ("login".equals(type)) {
            // 登录场景：邮箱必须已注册
            if (!emailExists) {
                throw new com.fish.common.exception.BusinessException("该邮箱尚未注册，请先注册");
            }
        } else if ("register".equals(type)) {
            // 注册场景：邮箱不能已存在
            if (emailExists) {
                throw new com.fish.common.exception.BusinessException("该邮箱已被注册，请直接登录");
            }
        }
        
        verificationCodeService.sendEmailCode(email);
        return Result.success("验证码已发送", null);
    }
    
    /**
     * 检查邮箱是否存在
     */
    @Operation(summary = "检查邮箱是否存在", description = "检查邮箱是否已被注册")
    @Parameter(name = "email", description = "邮箱地址", required = true, example = "user@example.com")
    @GetMapping("/check-email")
    public Result<Boolean> checkEmail(@RequestParam String email) {
        boolean exists = userService.checkEmailExists(email);
        return Result.success(exists);
    }
    
    /**
     * 邮箱注册
     */
    @Operation(summary = "邮箱注册", description = "使用邮箱验证码注册新用户")
    @PostMapping("/register/email")
    public Result<LoginVO> registerByEmail(@RequestBody com.fish.model.dto.EmailRegisterDTO registerDTO) {
        log.info("邮箱注册请求，邮箱：{}", registerDTO.getEmail());
        LoginVO loginVO = userService.registerByEmail(registerDTO);
        log.info("注册成功，返回数据 - accessToken存在: {}, refreshToken存在: {}, userInfo存在: {}", 
                loginVO.getAccessToken() != null, 
                loginVO.getRefreshToken() != null, 
                loginVO.getUserInfo() != null);
        Result<LoginVO> result = Result.success("注册成功", loginVO);
        log.info("返回结果 - code: {}, message: {}, data存在: {}", 
                result.getCode(), 
                result.getMessage(), 
                result.getData() != null);
        return result;
    }
    
    /**
     * 邮箱验证码登录
     */
    @Operation(summary = "邮箱验证码登录", description = "使用邮箱验证码登录系统")
    @PostMapping("/login/email")
    public Result<LoginVO> loginByEmail(@RequestBody com.fish.model.dto.EmailLoginDTO loginDTO) {
        log.info("邮箱验证码登录请求，邮箱：{}", loginDTO.getEmail());
        LoginVO loginVO = userService.loginByEmail(loginDTO);
        log.info("登录成功，返回数据 - accessToken存在: {}, refreshToken存在: {}, userInfo存在: {}", 
                loginVO.getAccessToken() != null, 
                loginVO.getRefreshToken() != null, 
                loginVO.getUserInfo() != null);
        Result<LoginVO> result = Result.success("登录成功", loginVO);
        log.info("返回结果 - code: {}, message: {}, data存在: {}", 
                result.getCode(), 
                result.getMessage(), 
                result.getData() != null);
        return result;
    }
    
    /**
     * 更新邮箱
     */
    @Operation(summary = "更新邮箱", description = "更新用户邮箱地址")
    @PutMapping("/update-email")
    public Result<Void> updateEmail(@RequestBody com.fish.model.dto.UpdateEmailDTO updateDTO) {
        log.info("更新邮箱请求，用户ID：{}，新邮箱：{}", updateDTO.getUserId(), updateDTO.getNewEmail());
        userService.updateEmail(updateDTO);
        return Result.success("邮箱更新成功", null);
    }
    
    /**
     * Refresh Token请求对象
     */
    public static class RefreshTokenRequest {
        private String refreshToken;
        
        public String getRefreshToken() {
            return refreshToken;
        }
        
        public void setRefreshToken(String refreshToken) {
            this.refreshToken = refreshToken;
        }
    }
}